use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::quote;
use syn::{DeriveInput, Expr, Fields, Lit, LitStr, Meta, Variant, parse_macro_input};

// 定义宏的入口点，指定支持status_code属性
#[proc_macro_derive(ImplIErrorCode, attributes(status_code))]
pub fn derive_error_code(input: TokenStream) -> TokenStream {
    // 解析输入的枚举定义
    let input = parse_macro_input!(input as DeriveInput);
    let enum_name = input.ident;

    // 确保是枚举类型
    let data = match &input.data {
        syn::Data::Enum(data) => data,
        _ => panic!("ImplIErrorCode 只能用于枚举类型"),
    };

    // 为每个枚举成员生成get_code方法的匹配分支
    let code_match_arms = data.variants.iter().map(|variant| {
        let variant_ident = &variant.ident;
        let variant_str = LitStr::new(&variant_ident.to_string(), Span::call_site());

        // 根据不同的字段类型生成对应的匹配模式
        match &variant.fields {
            Fields::Unit => {
                quote! {
                    #enum_name::#variant_ident => #variant_str
                }
            }
            Fields::Named(_) => {
                quote! {
                    #enum_name::#variant_ident { .. } => #variant_str
                }
            }
            Fields::Unnamed(_) => {
                quote! {
                    #enum_name::#variant_ident(..) => #variant_str
                }
            }
        }
    });

    // 为每个枚举成员生成status_code方法的匹配分支
    let status_code_match_arms = data.variants.iter().map(|variant| {
        let ident = &variant.ident;
        // 提取status_code属性，如果没有则panic（或提供默认值）
        let status_code = extract_status_code(variant).unwrap_or(200);

        // 根据不同的字段类型生成对应的匹配模式
        match &variant.fields {
            Fields::Unit => {
                quote! {
                    #enum_name::#ident => #status_code
                }
            }
            Fields::Named(_) => {
                quote! {
                    #enum_name::#ident { .. } => #status_code
                }
            }
            Fields::Unnamed(_) => {
                quote! {
                    #enum_name::#ident(..) => #status_code
                }
            }
        }
    });

    // 生成完整的impl代码
    let expanded = quote! {
        // 假设IErrorCode trait定义如下
        // pub trait IErrorCode {
        //     fn get_code(&self) -> &str;
        //     fn status_code(&self) -> u16;
        // }
        impl IErrorCode for #enum_name {
            /// 获取错误码字符串（枚举变体名称）
            fn get_code(&self) -> &str {
                match self {
                    #(#code_match_arms),*
                }
            }

            /// 获取HTTP状态码（从status_code属性提取）
            fn status_code(&self) -> u16 {
                match self {
                    #(#status_code_match_arms),*
                }
            }
        }
    };

    TokenStream::from(expanded)
}

/// 从枚举变体的属性中提取status_code值
fn extract_status_code(variant: &Variant) -> Option<u16> {
    for attr in &variant.attrs {
        // 解析属性为键值对形式
        if let Meta::NameValue(meta_name_value) = &attr.meta {
            // 检查属性名为"status_code"
            if meta_name_value.path.is_ident("status_code") {
                // 从表达式中提取字面量
                let expr = &meta_name_value.value;

                // 匹配表达式中的字面量（关键修复点）
                if let Expr::Lit(expr_lit) = expr {
                    // 从ExprLit中获取Lit
                    if let Lit::Int(lit_int) = &expr_lit.lit {
                        // 解析为u16
                        return lit_int.base10_parse::<u16>().ok();
                    }
                }
            }
        }
    }
    None
}
